﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;

using Moe.ECamel.Common.Entities;
using Moe.ECamel.Common.Contracts;

namespace Moe.ECamel.Server.BL
{
	public class ItemBL : ECamelBL
	{
		/// <summary>
		/// Default constructor for business logic component.
		/// </summary>
		/// <param name="dataContext">Data context to be used by this component's operations.</param>
		public ItemBL(ECamelDataContext dataContext)
			: base(dataContext)
		{
		}

		public SearchItemsResponse SearchItems(SearchItemsRequest request)
		{
			// Configure load options:
			DataLoadOptions loadOptions = new DataLoadOptions();
			loadOptions.LoadWith<Item>(i => i.ItemProperties);
			loadOptions.LoadWith<Item>(i => i.ItemType);
			ECamelDataContext adhocDC = new ECamelDataContext(dataContext.Connection);
			adhocDC.ObjectTrackingEnabled = false;
			adhocDC.LoadOptions = loadOptions;

			var items = (from i in adhocDC.Items
						where i.ItemTypeId == request.Template.ItemTypeId && 
						(i.CatalogNumber.Contains(request.Template.CatalogNumber)) &&
						(i.Title.Contains(request.Template.Title))
						select i).ToList();

			var result = new SearchItemsResponse {Items = new List<SearchItemResult>()};

			foreach (var item in items)
			{
				bool allPropertiesMatch = true;
				foreach (var ip in request.Template.ItemProperties)
				{
					if (!item.ItemProperties.Any(ip2 => ip2.ItemPropertyTypeId == ip.ItemPropertyTypeId && ip2.Value.Contains(ip.Value)))
					{
						allPropertiesMatch = false;
						break;
					}
				}
				if (allPropertiesMatch)
				{
					int itemId = item.ItemId;
					var query = from i in dataContext.Inventories
								where i.ItemId == itemId && i.IsActive && (request.LibraryId == null || request.LibraryId == i.LibraryId)
								select i;

					int totalCount = query.Count();
					int availableCount = query.Count(i => i.IsAvailable);
					result.Items.Add(new SearchItemResult {Item = item, NumOfCopies =  totalCount, NumOfAvailableCopies = availableCount});
				}
			}
			return result;
		}
		public Item GetItemById(int itemId)
		{
			var query = from i in dataContext.Items
			            where i.ItemId == itemId
			            select i;
			return query.SingleOrDefault();
		}

		public ECamelError CreateItem(Item item)
		{
			// Validate:
			ECamelError validationError = ValidateItem(item);
			if (validationError != null)
				return validationError;

			// Insert:
			dataContext.Items.InsertOnSubmit(item);

			// Return with no error:
			return null;
		}
		public ECamelError UpdateItem(Item item)
		{
			// Validate:
			ECamelError validationError = ValidateItem(item);
			if (validationError != null)
				return validationError;

			// Update:
			dataContext.Items.Attach(item, true);
			dataContext.ItemProperties.DeleteAllOnSubmit(dataContext.ItemProperties.Where(ip => ip.ItemId == item.ItemId));
			dataContext.ItemProperties.InsertAllOnSubmit(item.ItemProperties);

			// Return with no error:
			return null;
		}

		private ECamelError ValidateItem(Item item)
		{
			// Validate user details:
			ECamelError validationError = item.Validate();
			if (validationError != null)
				return validationError;

			// Validate catalog number is unique:
			int others = (from i in dataContext.Items
						  where i.CatalogNumber == item.CatalogNumber && i.ItemId != item.ItemId
						  select i.ItemId).Count();
			if (others > 0)
				return new ECamelError(MessageIds.ItemInvalidDuplicateCatalogNumber);

			return null;
		}
	}
}